package com.xvyy.tingshu.order.adapter.impl;

import com.xvyy.tingshu.account.client.UserAccountFeignClient;
import com.xvyy.tingshu.common.constant.SystemConstant;
import com.xvyy.tingshu.common.execption.TsException;
import com.xvyy.tingshu.common.rabbit.constant.MqConst;
import com.xvyy.tingshu.common.rabbit.service.RabbitService;
import com.xvyy.tingshu.common.result.Result;
import com.xvyy.tingshu.common.result.ResultCodeEnum;
import com.xvyy.tingshu.model.order.LocalMsg;
import com.xvyy.tingshu.order.adapter.PayWay;
import com.xvyy.tingshu.order.mapper.LocalMsgMapper;
import com.xvyy.tingshu.order.service.OrderInfoService;
import com.xvyy.tingshu.vo.account.AccountLockResultVo;
import com.xvyy.tingshu.vo.account.AccountLockVo;
import com.xvyy.tingshu.vo.order.OrderInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
//import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


/**
 * ClassName: RechargePayWayImpl
 * Package: com.xvyy.tingshu.order.adapter
 *
 * @Description: 充值支付方式适配器
 * @Author: xvyy
 * @Create: 2025/2/11 - 11:07
 * @Version: v1.0
 */
@Component
public class RechargePayImpl implements PayWay {

    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private UserAccountFeignClient userAccountFeignClient;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private LocalMsgMapper localMsgMapper;

    /**
     * 本地定时任务扫描本地消息表，发送解锁和扣减余额的消息
     * TODO 拓展：xxl-job 解决定时任务问题
     */
    @Scheduled(fixedDelay = 1000 * 60 * 60)
    public void scanLocalMsg() {
        // 查询本地消息表，状态为0的记录（未发送的消息）
        List<LocalMsg> localMsgList = localMsgMapper.selectList(new LambdaQueryWrapper<LocalMsg>().eq(LocalMsg::getStatus, 0));
        for (LocalMsg localMsg : localMsgList) {
            // 发送消息
            String msgContent = localMsg.getMsgContent();
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_UNLOCK, msgContent);
            // 兜底逻辑，兜底扣减余额
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_MINUS, msgContent);
        }
    }

    /**
     * xxl-job 解决定时任务问题
     * @param payWay
     * @return
     */
/*    @XXLJob("xxlJobScanLocalMsg")
    public void xXLJobScanLocalMsg(String payWay) {
        // 查询本地消息表，状态为0的记录（未发送的消息）
        List<LocalMsg> localMsgList = localMsgMapper.selectList(new LambdaQueryWrapper<LocalMsg>().eq(LocalMsg::getStatus, 0));
        for (LocalMsg localMsg : localMsgList) {
            // 发送消息
            String msgContent = localMsg.getMsgContent();
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_UNLOCK, msgContent);
            // 兜底逻辑，兜底扣减余额
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_MINUS, msgContent);
        }
    }*/

    @Override
    public Boolean supportPayWay(String payWay) {
        return SystemConstant.ORDER_PAY_ACCOUNT.equals(payWay);//余额支付方式
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
//    @GlobalTransactional(rollbackFor = Exception.class)
    public void payWay(OrderInfoVo orderInfoVo, String orderNo, Long userId) {
        // 0. 准备账户数据（封装账户数据）
        AccountLockVo accountLockVo = prepareAccountData(orderInfoVo, orderNo, userId);
        // 1.判断是否够用（rpc） 远程调用account微服务，判断余额是否够用，锁定账户余额和可用账户余额
        Result<AccountLockResultVo> accountLockResult = userAccountFeignClient.checkAndLockAccount(accountLockVo);
        Integer accountLockResultCode = accountLockResult.getCode();
        if (accountLockResultCode != 200) {throw new TsException(ResultCodeEnum.ACCOUNT_LOCK_ERROR);}
        try {
            // 2. 初始化本地消息表，先进行本地消息表插入数据，保证幂等性
            orderInfoService.saveLocalMsg(orderNo);
            // 3. 保存订单
            orderInfoService.saveOrderInfo(orderNo, orderInfoVo, userId);
            // 4. 扣减余额
            // account微服务minus发送扣减余额消息
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_MINUS, orderNo);
            // 5. 支付成功之后的业务逻辑
            orderInfoService.paySuccess(orderNo);
        } catch (TsException e) {
            // 6. 反向修改account微服务下的账户信息：unlock锁定账户余额和可用账户余额
            // 发送解锁消息 如果失败了，事务回滚，本地消息表没消息，不走这一段逻辑
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_UNLOCK, orderNo);
//            throw new TsException(ResultCodeEnum.ACCOUNT_LOCK_ERROR);//使用Seata一定要抛异常
        } catch (Exception e) {
            // 7. 继续扣钱 account微服务，发送minus消息，扣减余额，兜底逻辑
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_MINUS, orderNo);
        }
    }

    /**
     * 准备账户数据
     *
     * @param orderInfoVo
     * @param orderNo
     * @param userId
     * @return
     */
    private AccountLockVo prepareAccountData(OrderInfoVo orderInfoVo, String orderNo, Long userId) {
        AccountLockVo accountLockVo = new AccountLockVo();
        accountLockVo.setOrderNo(orderNo);
        accountLockVo.setUserId(userId);
        accountLockVo.setAmount(orderInfoVo.getOrderAmount());
        accountLockVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        return accountLockVo;
    }


}
